package top.zhangjianyong.blog.service.impl;

import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import top.zhangjianyong.blog.service.AntiHotlinkStatsService;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 防盗链统计服务实现类
 * 使用内存存储，适合简单场景
 *
 * @author zhangjianyong
 * @since 2024/12/19
 */
@Slf4j
@Service
public class AntiHotlinkStatsServiceImpl implements AntiHotlinkStatsService {

    /**
     * 攻击记录存储（IP -> 攻击信息列表）
     */
    private final Map<String, List<AttackRecord>> attackRecords = new ConcurrentHashMap<>();

    /**
     * 攻击记录
     */
    @Getter
    private static class AttackRecord {
        // getters
        private final String ip;
        private final String referer;
        private final String userAgent;
        private final String uri;
        private final String reason;
        private final LocalDateTime attackTime;

        public AttackRecord(String ip, String referer, String userAgent, String uri, String reason) {
            this.ip = ip;
            this.referer = referer;
            this.userAgent = userAgent;
            this.uri = uri;
            this.reason = reason;
            this.attackTime = LocalDateTime.now();
        }

    }

    @Override
    public void recordAttack(String ip, String referer, String userAgent, String uri, String reason) {
        try {
            AttackRecord record = new AttackRecord(ip, referer, userAgent, uri, reason);
            attackRecords.computeIfAbsent(ip, k -> new ArrayList<>()).add(record);

            // 清理过期数据（保留最近7天的数据）
            cleanupOldRecords();

            log.debug("记录防盗链攻击: IP={}, URI={}, Reason={}", ip, uri, reason);
        } catch (Exception e) {
            log.error("记录防盗链攻击失败", e);
        }
    }

    @Override
    public AttackStats getAttackStats(LocalDateTime startTime, LocalDateTime endTime) {
        AttackStats stats = new AttackStats();

        try {
            // 统计指定时间范围内的攻击
            List<AttackRecord> filteredRecords = attackRecords.values().stream()
                .flatMap(List::stream)
                .filter(record -> !record.getAttackTime().isBefore(startTime) && !record.getAttackTime().isAfter(endTime))
                .toList();

            stats.setTotalAttacks(filteredRecords.size());
            stats.setUniqueIps(filteredRecords.stream().map(AttackRecord::getIp).distinct().count());

            // 获取热门攻击IP
            Map<String, Long> ipCounts = filteredRecords.stream()
                .collect(Collectors.groupingBy(AttackRecord::getIp, Collectors.counting()));

            List<AttackIpStats> topIps = ipCounts.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .limit(10)
                .map(entry -> {
                    AttackIpStats ipStats = new AttackIpStats();
                    ipStats.setIp(entry.getKey());
                    ipStats.setAttackCount(entry.getValue());

                    // 获取最后攻击时间
                    LocalDateTime lastAttack = filteredRecords.stream()
                        .filter(record -> record.getIp().equals(entry.getKey()))
                        .map(AttackRecord::getAttackTime)
                        .max(LocalDateTime::compareTo)
                        .orElse(null);
                    ipStats.setLastAttackTime(lastAttack);

                    return ipStats;
                })
                .collect(Collectors.toList());

            stats.setTopIps(topIps);

        } catch (Exception e) {
            log.error("获取防盗链攻击统计失败", e);
        }

        return stats;
    }

    @Override
    public List<AttackIpStats> getTopAttackIps(int limit) {
        try {
            // 统计所有IP的攻击次数
            Map<String, Long> ipCounts = attackRecords.entrySet().stream()
                .collect(Collectors.toMap(
                    Map.Entry::getKey,
                    entry -> (long) entry.getValue().size()
                ));

            return ipCounts.entrySet().stream()
                .sorted(Map.Entry.<String, Long>comparingByValue().reversed())
                .limit(limit)
                .map(entry -> {
                    AttackIpStats ipStats = new AttackIpStats();
                    ipStats.setIp(entry.getKey());
                    ipStats.setAttackCount(entry.getValue());

                    // 获取最后攻击时间
                    LocalDateTime lastAttack = attackRecords.get(entry.getKey()).stream()
                        .map(AttackRecord::getAttackTime)
                        .max(LocalDateTime::compareTo)
                        .orElse(null);
                    ipStats.setLastAttackTime(lastAttack);

                    return ipStats;
                })
                .collect(Collectors.toList());

        } catch (Exception e) {
            log.error("获取热门攻击IP失败", e);
            return new ArrayList<>();
        }
    }

    /**
     * 清理过期数据（保留最近7天的数据）
     */
    private void cleanupOldRecords() {
        LocalDateTime cutoffTime = LocalDateTime.now().minusDays(7);

        attackRecords.entrySet().removeIf(entry -> {
            List<AttackRecord> records = entry.getValue();
            records.removeIf(record -> record.getAttackTime().isBefore(cutoffTime));
            return records.isEmpty();
        });
    }
} 